package com.renhe.utils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import java.util.regex.Pattern;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.Inflater;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.http.NameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;

public class Common{
	private static Logger logger = LoggerFactory.getLogger(Common.class);
	
	/* 跟Long.parseLong一样，但是Long.parseLong在解析如 0xfffffffffffff123 这样的字符串时会抛出异常 */
	public static long parse_long(String x){
		String up = x.substring(0, 8);
		String down = x.substring(8);
		
		long a = Long.parseLong(up, 16) << 32;
		long b = Long.parseLong(down, 16);
		return a+b;
	}
	
	/* 获取 [min, max] 的随机数 */
	private static Random r = new Random(System.currentTimeMillis());
	public static int rand(int min, int max){
		return (min + r.nextInt(max-min+1));
	}
	
	public static String show_time(long mill){
		return show_time(mill, "yyyy-MM-dd HH:mm:ss");
	}
	
	public static String show_time(long mill, String format){
		SimpleDateFormat f = new SimpleDateFormat(format);
		return f.format(new Date(mill));
	}
	
	public static String show_time(Date d){
		return show_time(d, "yyyy-MM-dd HH:mm:ss");
	}
	
	public static String show_time(Date d, String format){
		if(d == null)
			return "";
		SimpleDateFormat f = new SimpleDateFormat(format);
		return f.format(d);
	}
	
	public static String join(String[] ss, String split){
		if(ss == null || ss.length == 0)
			return "";
		StringBuffer sb = new StringBuffer();
		for(int i=0; i<ss.length; ++i){
			if(i != 0){
				sb.append(split);
			}
			sb.append(ss[i]);
		}
		return sb.toString();
	}
	
	public static long convert2Long(Object o){
		if(o == null)
			return 0;
		if(o instanceof Long) return ((Long)o).longValue();
		if(o instanceof Integer){
			int tmp = ((Integer)o).intValue();
			return (long)tmp;
		}
		
		String s = o.toString();
		boolean flag = false;
		StringBuffer m = new StringBuffer();
		for(int i=0; i<s.length(); ++i){
			char c = s.charAt(i);
			if(c >= '0' && c <= '9'){
				m.append(c);
				flag = true;
			}
			else{
				if(flag) break;
				else continue;
			}
		}
		return Long.parseLong(m.toString());
	}
	
	public static int convert2Int(Object o){
		long d = convert2Long(o);
		return (int)d;
	}
	
	public static boolean file_put_contents(String file, String content, boolean append){
		try{
			return file_put_contents(file, content.getBytes("UTF-8"), append);
		}catch(Exception e){
			logger.error("error", e);
			return false;
		}
	}
	public static boolean file_put_contents(String file, String content){
		return file_put_contents(file, content, false);
	}
	public static boolean file_put_contents(String file, byte[] bs, boolean append){
		FileOutputStream out = null;
		try{
			out = new FileOutputStream(file, append);
			out.write(bs);
			out.flush();
			return true;
		}catch(Exception e){
			logger.error("error", e);
			return false;
		}finally{
			if(out != null)
				try{out.close();}catch(Exception e){logger.error("error", e);}
		}
	}
	public static boolean file_put_contents(String file, byte[] bs){
		return file_put_contents(file, bs, false);
	}
	
	public static byte[] file_get_contents(String file){
		File f = new File(file);
		if(!f.exists())
			return null;
		
		int len = (int)f.length();
		byte[] bs = new byte[len];
		
		FileInputStream in = null;
		try{
			in = new FileInputStream(f);
			int n = 0, off = 0;
			while((n = in.read(bs, off, len)) != -1 && len != 0){
				off += n;
				len -= n;
			}
			return bs;
		}catch(Exception e){
			logger.error("error", e);
			return null;
		}finally{
			if(in != null)
				try{in.close();}catch(Exception e){logger.error("error", e);}
		}
	}
	public static String file_get_contents(String file, String encode){
		byte[] bs = file_get_contents(file);
		if(bs == null)
			return null;
		try{
			return new String(bs, encode);
		}catch(Exception e){
			return null;
		}
	}
	
	public static String[] array_filter(String[] arr){
		if(arr == null) return null;
		if(arr.length == 0) return arr;
		
		List<String> _list = new ArrayList<String>();
		for(String s : arr){
			if(StringUtils.isBlank(s) || StringUtils.isWhitespace(s)){
				continue;
			}
			_list.add(s.trim());
		}
		return _list.toArray(new String[0]);
	}
	
	public static String now(String format){
		Date now = new Date(System.currentTimeMillis());
		SimpleDateFormat f = new SimpleDateFormat(format);
		return f.format(now);
	}
	
	public static String now(){
		return now("yyyy-MM-dd HH:mm:ss");
	}
	
	public static String newString(byte[] bs, String enc){
		try{
			return new String(bs, enc);
		}catch(Exception e){
			return null;
		}
	}
	
	public static String url_encode(String s, String enc){
		try{
			return URLEncoder.encode(s, enc);
		}catch(Exception e){
			return null;
		}
	}
	
	public static String url_encode(String s){
		return url_encode(s, "UTF-8");
	}
	
	public static String url_decode(String s, String enc){
		try{
			return URLDecoder.decode(s, enc);
		}catch(Exception e){
			return null;
		}
	}
	
	public static String url_decode(String s){
		return url_decode(s, "UTF-8");
	}
	
	public static String create_imei(){
		String s = "";
		String x = "1234567890";
		for(int i=0; i<15; ++i){
			s += x.charAt(Common.rand(0, x.length()-1));
		}
		return s;
	}
	
	public static byte[] decompress(byte[] value) throws Exception {
		ByteArrayOutputStream bos = new ByteArrayOutputStream(value.length);
		Inflater decompressor = new Inflater();
		try {
			decompressor.setInput(value);
			final byte[] buf = new byte[1024];
			while (!decompressor.finished()) {
				int count = decompressor.inflate(buf);
				bos.write(buf, 0, count);
			}
		} finally {
			decompressor.end();
		}

		return bos.toByteArray();
	}

	public static byte[] compress(byte[] value, int offset, int length,
			int compressionLevel) {
		ByteArrayOutputStream bos = new ByteArrayOutputStream(length);
		Deflater compressor = new Deflater();
		try {
			compressor.setLevel(compressionLevel); // 将当前压缩级别设置为指定值。
			compressor.setInput(value, offset, length);
			compressor.finish(); // 调用时，指示压缩应当以输入缓冲区的当前内容结尾。

			// Compress the data
			final byte[] buf = new byte[1024];
			while (!compressor.finished()) {
				// 如果已到达压缩数据输出流的结尾，则返回 true。
				int count = compressor.deflate(buf);
				// 使用压缩数据填充指定缓冲区。
				bos.write(buf, 0, count);
			}
		} finally {
			compressor.end(); // 关闭解压缩器并放弃所有未处理的输入。
		}

		return bos.toByteArray();
	}

	public static byte[] compress(byte[] value, int offset, int length) {
		// 最佳压缩的压缩级别
		return compress(value, offset, length, Deflater.BEST_COMPRESSION);
	}

	public static byte[] compress(byte[] value) {
		return compress(value, 0, value.length, Deflater.BEST_COMPRESSION);
	}
	
	public static String http_build_query(KeyValue... kvs){
		if(kvs == null || kvs.length == 0)
			return "";
		
		try{
			StringBuffer buf = new StringBuffer();
			buf.append(kvs[0].getKey()).append("=").append(kvs[0].getValue());
			for(int i=1; i<kvs.length; ++i){
				buf.append("&").append(kvs[i].getKey()).append("=").append(URLEncoder.encode(String.valueOf(kvs[i].getValue()), "UTF-8"));
			}
			return buf.toString();
		}catch(Exception e){
			return null;
		}
	}
	
	public static Map<String, String> parseQueryString(String url){
		Map<String, String> map = new TreeMap();
		try{
			URL urlObj = new URL(url);
			String queryString = urlObj.getQuery();
			String[] ss = queryString.split("&");
			for(String s : ss){
				String[] ss2 = s.split("=");
				if(ss2.length == 2){
					String v = url_decode(ss2[1]);
					map.put(ss2[0], v==null ? "" : v);
				}
			}
			return map;
		}catch(Exception e){
			logger.error("parseQueryString error", e);
			return null;
		}
	}
	
	public static String http_build_query(List<NameValuePair> kvs){
		if(kvs == null || kvs.size() == 0)
			return "";
		
		try{
			StringBuffer buf = new StringBuffer();
			buf.append(kvs.get(0).getName()).append("=").append(kvs.get(0).getValue());
			for(int i=1; i<kvs.size(); ++i){
				buf.append("&").append(kvs.get(i).getName()).append("=").append(URLEncoder.encode(String.valueOf(kvs.get(i).getValue()), "UTF-8"));
			}
			return buf.toString();
		}catch(Exception e){
			return null;
		}
	}
	
	public static String md5(byte[] bs){
		MessageDigest md5 = null;
		try {
			md5 = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}

		md5.update(bs);
		byte[] rtn = md5.digest();
		return ByteHelper.bytesToHexString(rtn);
	}
	
	public static String md5(String s){
		try{
			byte[] bs = s.getBytes("UTF-8");
			return md5(bs);
		}catch(Exception e){
			e.printStackTrace();
			return null;
		}
	}
	
	public static byte[] gzencode(byte[] bs){
		try{
			ByteArrayOutputStream bout = new ByteArrayOutputStream();
			GZIPOutputStream out = new GZIPOutputStream(bout);
			out.write(bs);
			out.finish();
			byte[] rtn = bout.toByteArray();
			
			out.close();
			return rtn;
		}catch(Exception e){
			e.printStackTrace();
			return null;
		}
	}
	
	public static byte[] gzdecode(byte[] bs){
        try {
        	GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(bs));
        	ByteArrayOutputStream out = new ByteArrayOutputStream();
        	
        	byte[] buf = new byte[1024];
            int len;
            while((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            byte[] rtn = out.toByteArray();
            
            in.close();
            out.close();
            return rtn;
        } catch(Exception e) {
        	e.printStackTrace();
        	return null;
        }
	}
	
	public static String createRoleName(int length){
		String x = "人之初性本善性相近习相远苟不教性乃迁教之道贵以专昔孟母择邻处子不学断机杼窦燕山有义方教五子名俱扬养不教父之过教不严师之惰子不学非所宜幼不学老何为？玉不琢不成器人不学不知义为人子方少时亲师友习礼仪香九龄能温席孝于亲所当执融四岁能让梨弟于长宜先知首孝悌次见闻知某数识某文一而十十而百百而千千而万三才者天地人三光者日月星三纲者君臣义父子亲夫妇顺曰春夏曰秋冬此四时运不穷曰南北曰西东此四方应乎中曰水火木金土此五行本乎数十干者甲至癸十二支子至亥曰黄道日所躔曰赤道当中权赤道下温暖极我中华在东北曰江河曰淮济此四渎水之纪曰岱华嵩恒衡此五岳山之名曰士农曰工商此四民国之良曰仁义礼智信此五常不容紊地所生有草木此植物遍水陆有虫鱼有鸟兽此动物能飞走稻粱菽麦黍稷此六谷人所食马牛羊鸡犬豕此六畜人所饲曰喜怒曰哀惧爱恶欲七情具青赤黄及白黑此五色目所识酸苦甘及辛咸此五味口所含膻焦香及腥朽此五臭鼻所嗅匏土革木石金丝与竹乃八音曰平上曰去入此四声宜调协高曾祖父而身身而子子而孙自子孙至玄曾乃九族人之伦父子恩夫妇从兄则友弟则恭；长幼序友与朋君则敬臣则忠此十义人所同当顺叙勿违背斩齐衰大小幼至缌麻五服终礼乐射御书数古六艺今不具唯书学人共遵既识字讲说文有古文大小篆隶草继不可乱若广学惧其繁但略说能知源凡训蒙须讲究详训诂明句读为学者必有初小学终至四书论语者二十篇群弟子记善言孟子者七篇止讲道德说仁义作中庸子思笔中不偏庸不易作大学乃曾子自修齐至平治孝经通四书熟如六经始可读诗书易礼春秋号六经当讲究有连山有归藏有周易三易详有典谟有训诰有誓命书之奥我周公作周礼著六官存治体大小戴注礼记述圣言礼乐备曰国风曰雅颂号四诗当讽咏诗既亡春秋作寓褒贬别善恶三传者有公羊有左氏有谷梁经既明方读子撮其要记其事五子者有荀扬文中子及老庄经子通读诸史考世系知终始自羲农至黄帝号三皇居上世唐有虞号二帝相揖逊称盛世夏有禹商有汤周文武称三王夏传子家天下四百载迁夏社汤伐夏国号商六百载至纣亡周武王始诛纣八百载最长久周辙东王纲坠逞干戈尚游说始春秋终战国五霸强七雄出蠃秦氏始兼并传二世楚汉争高祖兴汉业建至孝平王莽篡光武兴为东汉四百年终于献魏蜀吴争汉鼎号三国迄两晋宋齐继梁陈承为南朝都金陵北元魏分东西宇文周与高齐迨至隋一土宇不再传失统绪唐高祖起义师除隋乱创国基二十传三百载梁灭之国乃改梁唐晋及汉周称五代皆有由炎宋兴受周禅十八传南北混辽与金皆称帝元灭金绝宋世舆图广超前代九十载国祚废太祖兴国大明号洪武都金陵迨成祖迁燕京十六世至崇祯权阉肆寇如林李闯出神器焚清世祖膺景命靖四方克大定由康雍历乾嘉民安富治绩夸道咸间变乱起始英法扰都鄙同光后宣统弱传九帝满清殁革命兴废帝制立宪法建民国古今史全在兹载治乱知兴衰史虽繁读有次史记一汉书二后汉三国志四兼证经参通鉴读史者考实录通古今若亲目口而诵心而惟朝于斯夕于斯昔仲尼师项橐古圣贤尚勤学赵中令读鲁论彼既仕学且勤彼蒲编削竹简彼无书且知勉头悬梁锥刺股彼不教自勤苦如囊萤如映雪家虽贫学不辍如负薪如挂角身虽劳犹苦卓苏老泉二十七始发愤读书籍彼既老犹悔迟尔小生宜早思若梁灏八十二对大廷魁多士彼既成众称异尔小生宜立志莹八岁能咏诗泌七岁能赋棋彼颖悟人称奇尔幼学当效之蔡文姬能辨琴谢道韫能咏吟彼女子且聪敏尔男子当自警唐刘晏方七岁举神童作正字彼虽幼身已仕尔幼学勉而致有为者亦若是犬守夜鸡司晨苟不学曷为人蚕吐丝蜂酿蜜人不学不如物幼而学壮而行上致君下泽民扬名声显父母光于前裕于后人遗子金满籯我教子惟一经勤有功戏无益戒之哉宜勉力";
		String name = "";
		for(int i=0; i<length; ++i){
			name += x.charAt(rand(0, x.length()));
		}
		return name;
	}
	
	public static int readStream(InputStream is, byte[] bytes){
		try{
	        int nRead = 1;  
	        int nTotalRead = 0;  
	        while (nRead > 0) {  
	            nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);  
	            if (nRead > 0)  
	                nTotalRead = nTotalRead + nRead;  
	        }
	        return nTotalRead;
		}catch(IOException e){
			e.printStackTrace();
			return -1;
		}
	}
	

	/**
	 * 重试3次的POST请求
	 * @param url
	 * @param data
	 * @return
	 */
	public static String httpPost(URLConnectionHttpFetcher fetcher, String url, String data){
		int count = 3;
		while(count-- > 0){
			String content = fetcher.posts(url, data);
			if(StringUtils.isBlank(content))
				continue;
			
			try{Thread.sleep(3000);}catch(Exception e){e.printStackTrace();}
			
			return content;
		}
		return null;
	}
	
	//重启当前机器的IP，需要外部脚本配合
	public static void exec(String cmd, StringBuffer out){
		Process process = null;
		try{
			process = Runtime.getRuntime().exec(cmd);
			OutputStream os = process.getOutputStream();
			os.write((cmd + "\necho '__finish__'\n").getBytes("UTF-8"));
			os.flush();
			
			// 等待进程执行完毕，简单粗暴快速有效！！！
			BufferedReader r = new BufferedReader(new InputStreamReader(process.getInputStream()));
			String line = null;
			while ((line = r.readLine()) != null) {
				if("__finish__".equals(line)) {
					break;
				}
				
				if(out != null) out.append(line);
			}
			r.close();
		}catch(Exception e){
			logger.error("error", e);
		}finally{
			if(process != null){
				process.destroy();
			}
		}
	}
	
	public static <T> boolean in(T a, T[] bs){
		for(T b : bs){
			if(a.equals(b))
				return true;
		}
		return false;
	}

	public static JSONObject buildResp(int code, String msg, KeyValue... params){
		JSONObject json = new JSONObject();
		json.put("code", code);
		json.put("msg", msg);
		for(KeyValue p : params){
			json.put(p.getKey(), p.getValue());
		}
		return json;
	}
	
	public static void sleep(int secs){
		msleep(secs*1000);
	}
	
	public static void msleep(long t){
		try{Thread.sleep(t);}catch(Exception e){e.printStackTrace();}
	}
	

	private static Pattern MOB_P = Pattern.compile("^1[0-9]{10}");
	public static boolean isMobileAccount(String str) {
		// 不支持手机号
		if (MOB_P.matcher(str).matches()) {
			return true;
		}
		return false;
	}
}
